#include "Logging.h"

#include "AsyncLogging.h"
#include "CurrentThread.h"
#include "thread.h"

#include <iostream>
#include <pthread.h>
#include <string>
#include <sys/time.h>  //这是POSIX 系统的系统调用的时间函数头文件，提供更高精度的时间函数
#include <time.h>      //这对时间函数的头文件

/*
    time.h头文件中定义了tm结构体，tm结构体中定义了年月日时分秒等时间信息，time_t是一个长整型，用来存储从1970年1月1日0时0分0秒到现在的秒数。
    首先需要获取time_t类型的时间，然后通过localtime函数将time_t类型的时间转换为tm结构体类型的时间。
    然后通过tm结构体中的成员变量获取年月日时分秒等时间信息。

    struct tm
    {
        int tm_sec;  //秒，正常范围0-59， 但允许至61
        int tm_min;  //分钟，0-59
        int tm_hour;  //小时， 0-23
        int tm_mday;  //日，即一个月中的第几天，1-31
        int tm_mon;  //月， 从一月算起，0-11
        int tm_year;  //年， 从1900年算起
        int tm_wday;  //星期，一周中的第几天， 从星期日算起，0-6
        int tm_yday;  //从每年的1月1日算起的天数，0-365
        int tm_isdst;  //日光节约时间的旗标
     <sys/time.h> 头文件中定义了struct timeval 结构体，struct timezone 结构体，struct itimerval 结构体，struct timespec 结构体等。
        struct timeval 结构体用来存储时间值，其中包括秒和微秒两部分；
        struct timezone 结构体用来存储时区信息；
        struct itimerval 结构体用来存储定时器的时间间隔；
        struct timespec 结构体用来存储时间值。

    struct timeval
    {
        time_t tv_sec;  //秒
        suseconds_t tv_usec;  //微秒
    };
    struct timezone
    {
        int tz_minuteswest;  //和Greenwich 时间差了多少分钟
        int tz_dsttime;  //日光节约时间的状态
    };
    struct itimerval
    {
        struct timeval it_interval;  //计时器重启动的间隔时间
        struct timeval it_value;  //计时器开始的时间
    };
    struct timespec
    {
        time_t tv_sec;  //秒
        long tv_nsec;  //纳秒
    };


*/

namespace droneswarm
{
    /*
组件解析：pthread_once_t once_control_ = PTHREAD_ONCE_INIT;：这里定义了一个名为 once_control_ 的静态变量，
类型为 pthread_once_t。它被初始化为PTHREAD_ONCE_INIT，这是一个编译时宏，用于初始化 pthread_once_t 类型的变量。

功能和使用方式
pthread_once_t 类型的变量通常与 pthread_once 函数一起使用。pthread_once 函数接收两个参数：一个 pthread_once_t
类型的变量和一个无参函数指针。当多个线程尝试执行由 pthread_once 调用的函数时，pthread_once
保证该函数在程序执行期间只被执行一次，即使在多线程环境中，也能保证线程安全。
*/
    static pthread_once_t once_control = PTHREAD_ONCE_INIT;
    static AsyncLogging *AsyncLogger;  //静态全局变量，全局中只有一个AsyncLogging对象，同时具有内部链接性

    std::string Logger::logFileName_ = "../systemLog/Log.log";  //初始化静态成员变量，执行日志文件的路径
    
    void once_init()
    {
        //创建日志核心类AsyncLogging对象
        AsyncLogger = new AsyncLogging( Logger::getLogFileName() );
        //启动日志线程
        AsyncLogger->start();
    }

    void output( const char *msg, int len )
    {
        // pthread_once函数通常与pthread_once_t类型的变量一起使用，以确保函数在程序执行期间只被执行一次。
        // pthread_once函数接收两个参数：一个pthread_once_t类型的变量和一个无参函数指针。
        // 当多个线程尝试执行由pthread_once调用的函数时，pthread_once保证该函数在程序执行期间只被执行一次，
        //即使在多线程环境中，也能保证线程安全。
        pthread_once( &once_control, once_init );
        //改方法是往缓冲区中写入数据，而将缓冲区中的数据写入到文件中是在另一个线程中进行的。
        AsyncLogger->append( msg, len );
    }

    Logger::Impl::Impl( const char *fileName, int line )
        : stream_()  //初始化LogStream对象
        , line_( line )
        , basename_( fileName )
    {
        formatTime();  //格式化时间
    }

    //这个方法的作用是将时间格式化输出到LogStream对象中。
    void Logger::Impl::formatTime()
    {
        struct timeval tv;
        time_t time;
        char str_t[ 26 ] = { 0 };
        gettimeofday( &tv, NULL );  //获取当前时间
        time = tv.tv_sec;
        struct tm *p_time = localtime( &time );              //将time_t类型的时间转换为tm结构体类型的时间
        strftime( str_t, 26, "%Y-%m-%d %H:%M:%S", p_time );  //格式化时间
        stream_ << str_t << " ";
    }

    Logger::Logger( const char *fileName, int line )
        : impl_( fileName, line )
    {
    }

    Logger::~Logger()
    {
        impl_.stream_ << " -- " << impl_.basename_ << ':' << impl_.line_ << '\n';
        //这里是获取LogStream对象中的数据（这些数据都是格式化好了的），然后将数据写入到文件中。
        const LogStream::Buffer &buf( stream().buffer() );
        output( buf.data(), buf.length() );
    }
}  // namespace droneswarm
